/*
Another game of life with SDL renderer.
Copyright (C) 2009-2010  Julien CLEMENT (andematunum@gmail.com)
*/
/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "Cell.h"
#include "Utils.h"
#include "LifeRules.h"

#define NULL 0

#include <iostream>
using namespace std;

Cell::
Cell () : _neighborIndex(0),
		  _r(0), _g(0), _b(0),
		  _mate(NULL) {

	die();
	for (int k=0; k<8; k++) { 
		_neighbors[k] = NULL;
	}	
}

Cell::
~Cell () {
	die();
	for (int k=0; k<8; k++) { 
		_neighbors[k] = NULL;
	}
	_neighborIndex = 0;
	_mate    = NULL;
}

void
Cell::
initRandom (void) {
	bool flag;
	rand_bool(flag);
	if (flag == true) {
		get_born();
	}
	else {
		die();
	}
}

void
Cell::
initRandomColor (void) {
	bool flag;
	rand_bool(flag);
	if (flag == true) {
		rand_rgb(_r,_g,_b);
	}
	else {
		die();
	}
}

void
Cell::
getColor (unsigned int& r, unsigned int& g, unsigned int& b) {
	r = _r;
	g = _g;
	b = _b;
}

void
Cell::
die (void) {
	_r = 0;
	_g = 0;
	_b = 0;
}

void
Cell::
get_born (unsigned int r, unsigned int g, unsigned int b) {
	_r = r;
	_g = g;
	_b = b;
}

bool
Cell::
dead (void) {
	return (_r+_g+_b == 0);
}

bool
Cell::
alive (void) {
	return !dead();
}

void
Cell::
addNeighbor (Cell *neighbor) {
	if (neighbor == NULL) {
		return;
	}
	_neighbors[ _neighborIndex++ ] = neighbor;
}

void
Cell::
setMate (Cell *mate) {
	_mate = mate;
}

void
Cell::
evolve (bool& changed) {
	_mate->_cpy();
	// Update the state according to the previous changes
	changed = false;

	// Random mutation: die or birth
	/*if (rand() >= 0.9999) {
		if (alive()) {
			_mate->die();
		}
		else {
			_mate->get_born();
		}
		changed = true;
		return;
	}*/

	if (alive()) {
		int countAlives = 0;
		for (int k=0; k < _neighborIndex; k++) {
			Cell *cell = _neighbors[k];
			if (cell->alive()) {
				countAlives++;
			}
		}
		if ((countAlives <= UNDER_POPULATED) || (countAlives >= OVER_POPULATED)) {
			changed = true;
			_mate->die();
		}
	} else {
		int countAlives = 0;
		for (int k=0; k < _neighborIndex; k++) {
			Cell *cell = _neighbors[k];
			if (cell->alive()) {
				countAlives++;
			}
		}
		if (countAlives == BIRTH) {
			changed = true;
			_mate->get_born();
		}
	}
}

void
Cell::
evolveColor (bool& changed) {
	_mate->_cpy();
	// Update the state according to the previous changes
	changed = false;

	// Random mutation: die or birth
	/*if (rand() >= 0.999) {
		if (alive()) {
			_mate->die();
		}
		else {
			_mate->get_born();
		}
		changed = true;
		return;
	}*/

	if (alive()) {
		int countAlives = 0;
		for (int k=0; k < _neighborIndex; k++) {
			Cell *cell = _neighbors[k];
			if (cell->alive()) {
				countAlives++;
			}
		}
		if ((countAlives <= UNDER_POPULATED) || (countAlives >= OVER_POPULATED)) {
			changed = true;
			_mate->die();
		}
	} else {
		int countAlives = 0;
		int mr = 0, mg = 0, mb = 0;
		for (int k=0; k < _neighborIndex; k++) {
			Cell *cell = _neighbors[k];
			
			if (cell->alive()) {
				countAlives++;
				mr += cell->_r;
				mg += cell->_g;
				mb += cell->_b;
			}
		}
		if (countAlives == BIRTH) {
			changed = true;
			_mate->get_born((unsigned int)(mr/countAlives), (unsigned int)(mg/countAlives), (unsigned int)(mb/countAlives));
		}
	}
}

inline 
void
Cell::
_cpy (void) {
	_r = _mate->_r;
	_g = _mate->_g;
	_b = _mate->_b;
}

